Joining datasets
Ao analisar dados, é comum a necessidade de combinar conjuntos de dados relacionados. Os verbos join nos darão uma maneira de fazer isso. Para todas as junções, devemos estabelecer uma correspondência ou correspondência entre cada caso na tabela da esquerda e zero ou mais casos na tabela da direita.
Uma correspondência entre um caso na tabela left e um caso na tabela right é feita com base nos valores em pares de variáveis correspondentes.
- Você especifica quais pares usar.
- Um par é uma variável da tabela da esquerda e uma variável da tabela da direita ou um conjunto de variáveis da tabela da esquerda e da direita.
- Os casos devem ter valores exatamente iguais no par para que uma correspondência seja feita.
Quando juntamos conjuntos de dados, o formato geral é
onde left_dataset eright_dataset são datasets, <JOIN> é o tipo específico de junção, e <HOW TO JOIN> dá informações detalhadas sobre como fazê-lo.
O argumento by informa como juntar os dois conjuntos de dados, especificamente com quais variáveis ele deve corresponder. Se as variáveis estiverem os mesmos nomes, só precisamos escrever o nome dessa variável, entre aspas: by =" variable_name ".
Se as duas variáveis a serem correspondidas têm nomes diferentes nos dois conjuntos de dados, podemos escrever by = c (" nome1 "=" nome2 "), onde nome1 é a variável no conjunto de dados esquerdo a ser correspondido aonome2variável no conjunto de dados correto.
Também podemos corresponder em várias variáveis usando by = c (" nome1 "=" nome2 "," nome1a "=" nome2a "), onde os nomes à esquerda dos iguais são variáveis do conjunto de dados esquerdo e aqueles no à direita dos iguais são do conjunto de dados certo.
Se by = for omitido de uma junção, então R realizará uma * junção natural *, que combina os dois conjuntos de dados por todas as variáveis que eles têm em comum. É uma boa prática sempre incluir by =.
Vamos discutir os diferentes tipos de junções.
Mutating joins
A primeira classe de junções são junções mutantes, que adicionam novas variáveis (colunas) à tabela de dados esquerda a partir de observações correspondentes na tabela direita.
A principal diferença nas três opções de junção mutante nesta classe é como elas respondem às seguintes perguntas:
- O que acontece quando um caso na tabela da direita não tem correspondências na tabela da esquerda?
- O que acontece quando um caso na tabela da esquerda não tem correspondências na tabela da direita?
Três funções de junção mutantes:
left_join() : a saída tem todos os casos da esquerda, independentemente se houver uma correspondência na direita, mas descarta quaisquer casos na direita que não tenham uma correspondência na esquerda. (Há também uma função ** right_join () ** que faz o oposto.)
inner_join(): a saída tem apenas os casos da esquerda com uma correspondência à direita. 
full_join():a saída tem todos os casos da esquerda e da direita. Isso é menos comum do que os dois primeiros operadores de associação.
Quando há várias correspondências na tabela da direita para um caso específico na tabela da esquerda, todos os três desses operadores de junção mutante produzem um caso separado na nova tabela para cada uma das correspondências da direita.
Exemplos
Primeiro, crie dois pequenos conjuntos de dados:
- Comece com
general_info e left_join() o pet_info by person_id:
A tabela resultante tem 10 linhas de dados - as 10 observações de general_info. Existem valores ausentes para pet_owner paraperson_id que estavam na tabela general_info e não na tabelapet_info.
** ??? ** Como os resultados mudariam se right_join () fosse usado no código acima em vez de left_join ()?
- Comece com
general_info einner_join ()opet_info por person_id:
A tabela resultante tem apenas 6 linhas com as observações que estão em general_info epet_info.
- Comece com
general_info efull_join ()opet_info por person_id:
A tabela resultante possui 15 linhas. Estão faltando valores para pet_owner paraperson_id que estavam na tabela general_info e não na tabelapet_info, e estão faltando valores para idade ealuguel para person_id que estavam na tabela pet_info e não na tabelageneral_info.
Filtering joins
A segunda classe de junções são junções de filtragem, que selecionam casos específicos da tabela da esquerda com base em se eles correspondem a uma observação na tabela da direita.
** semi_join () **: descarta quaisquer casos na tabela da esquerda que não tenham uma correspondência na tabela da direita. Se houver várias correspondências de casos da direita para um caso da esquerda, ele mantém apenas uma cópia do caso da esquerda.
anti_join(): descarta quaisquer casos na tabela da esquerda que tenham uma correspondência na tabela da direita.
Examplo
Eles usam os dados de exemplo da seção anterior
Um semi_join () é usado para encontrar a idade e o status do aluguel (informações na tabela general_info) para os proprietários de animais de estimação:
Isso retorna uma tabela com 3 linhas. Uma vez que são mesas pequenas, você deve verificar isso manualmente. Observe também que não pressionei enter após %>% dentro de semi_join (). Este é um caso em que o deixamos na mesma linha para torná-lo mais legível.
Use um anti_join () para encontrar a idade e o status do aluguel (informações na tabela general_info) para pessoas que não são donos confirmados de animais de estimação (observe que isso inclui desconhecidos):
Demo video
Agora assista ao vídeo abaixo que irá guiá-lo por alguns exemplos de codificação mais avançados (além de uma participação especial de minha filha, Hadley). Os arquivos R Markdown para download para acompanhar são encontrados abaixo do vídeo pivotante.
Sua vez!
Exercise 1: mutating join
Exercício 1: mutação de junção
Resuma os dados garden_harvest para encontrar a colheita total em libras para cada variedade de vegetais e, em seguida, tente adicionar a parcela da tabelagarden_planting. Isso não sairá perfeitamente. Qual é o problema? Como você pode consertar isso?
Exercício 2: mutação de junção
Gostaria de saber quanto dinheiro “economizei” com a jardinagem, para cada tipo de vegetal. Descreva como eu poderia usar os conjuntos de dados garden_harvest egarden_spending, junto com dados de algum lugar como [este] (https://products.wholefoodsmarket.com/search?sort=relevance&store=10542) para responder a esta pergunta. Você pode responder isso em palavras, referenciando várias funções de junção. Você não precisa do código R, mas pode fornecer algum se for útil.
Exercício 3: junção de filtragem
Exclua as variedades de vegetais de colheita_do_jardim que estão nas parcelas M e H.
LS0tDQp0aXRsZTogIkF1bGEgSm9pbnMiDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCmVuY29kZTogIlVURi04Ig0KLS0tDQoNCiMjIFNldHVwDQoNCmBgYHtyIHNldHVwfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KA0KCW1lc3NhZ2UgPSBGQUxTRSwNCgl3YXJuaW5nID0gRkFMU0UsDQoJaW5jbHVkZSA9IEZBTFNFDQopDQpgYGANCg0KYGBge3IgbGlicmFyaWVzfQ0KbGlicmFyeSh0aWR5dmVyc2UpICAgICAjIGZvciBkYXRhIGNsZWFuaW5nIGFuZCBwbG90dGluZw0KbGlicmFyeShsdWJyaWRhdGUpICAgICAjIGZvciBkYXRlIG1hbmlwdWxhdGlvbg0KbGlicmFyeShwYWxtZXJwZW5ndWlucykjIGZvciBQYWxtZXIgcGVuZ3VpbiBkYXRhDQpsaWJyYXJ5KGRwbHlyKQ0KYGBgDQoNCg0KYGBge3IgZGF0YX0NCiMgTGlzYSdzIGdhcmRlbiBkYXRhDQojIFBhbG1lciBwZW5ndWlucw0KZGF0YSgicGVuZ3VpbnMiKQ0KDQojIFVTIHR1aXRpb24gYnkgc3RhdGUgZGF0YQ0KdXNfYXZnX3R1aXRpb24gPC0gcmVhZF9jc3YoImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3MvOWUwcGFyYWRjd3Z1emxsL3VzX2F2Z190dWl0aW9uLmNzdj9kbD0xIikgJT4lIA0KICAgbXV0YXRlKGFjcm9zcyhzdGFydHNfd2l0aCgiMjAiKSwgcGFyc2VfbnVtYmVyKSkNCmBgYA0KDQojIyBNZXRhcyBkZSBhcHJlbmRpemFnZW0NCg0KQXDDs3MgZXN0ZSB0dXRvcmlhbCwgdm9jw6ogZGV2ZSBzZXIgY2FwYXogZGUgZmF6ZXIgbyBzZWd1aW50ZToNCg0KKiBKdW50ZSB0YWJlbGFzIGRlIGRhZG9zIHVzYW5kbyBhcyBmdW7Dp8O1ZXMgZGUganVuw6fDo28gZHBseXIgZSBlbnRlbmRhIGFzIGRpZmVyZW7Dp2FzIGVudHJlIG9zIGRpZmVhbHVndWVsZXMgdGlwb3MgZGUganVuw6fDtWVzLg0KKiBVc2UgdsOhcmlhcyBmdW7Dp8O1ZXMgZm9yY2F0cywgaW5jbHVpbmRvIGFxdWVsYXMgbsOjbyBhYm9yZGFkYXMgbm8gdHV0b3JpYWwsIHBhcmEgYWx0ZXJhciBhIG9yZGVtIG91IG9zIHZhbG9yZXMgZG9zIG7DrXZlaXMgZGFzIHZhcmnDoXZlaXMgY2F0ZWfDs3JpY2FzLg0KKiBVc2UgYXMgZnVuw6fDtWVzIHN0cmluZ3IgYWJvcmRhZGFzIG5lc3RlIHR1dG9yaWFsIChhbMOpbSBkZSBgc2VwYXJhdGUoKWApIGUgc2FpYmEgb25kZSBlbmNvbnRyYXIgaW5mb3JtYcOnw7VlcyBzb2JyZSBvdXRyYXMgZnVuw6fDtWVzICpzdHJpbmdyKiAoRElDQTogYSBmb2xoYSBkZSBjaGVhdHNoZWV0IMOpIHVtIMOzdGltbyBjb21lw6dvKS4NCg0KDQojIyBKb2luaW5nIGRhdGFzZXRzDQoNCkFvIGFuYWxpc2FyIGRhZG9zLCDDqSBjb211bSBhIG5lY2Vzc2lkYWRlIGRlIGNvbWJpbmFyIGNvbmp1bnRvcyBkZSBkYWRvcyByZWxhY2lvbmFkb3MuIE9zIHZlcmJvcyBgam9pbmAgbm9zIGRhcsOjbyB1bWEgbWFuZWlyYSBkZSBmYXplciBpc3NvLiBQYXJhIHRvZGFzIGFzIGp1bsOnw7VlcywgZGV2ZW1vcyBlc3RhYmVsZWNlciB1bWEgY29ycmVzcG9uZMOqbmNpYSBvdSBjb3JyZXNwb25kw6puY2lhIGVudHJlIGNhZGEgY2FzbyBuYSB0YWJlbGEgZGEgZXNxdWVyZGEgZSB6ZXJvIG91IG1haXMgY2Fzb3MgbmEgdGFiZWxhIGRhIGRpcmVpdGEuDQoNClVtYSBjb3JyZXNwb25kw6puY2lhIGVudHJlIHVtIGNhc28gbmEgdGFiZWxhICpsZWZ0KiBlIHVtIGNhc28gbmEgdGFiZWxhICpyaWdodCogw6kgZmVpdGEgY29tIGJhc2Ugbm9zIHZhbG9yZXMgZW0gcGFyZXMgZGUgdmFyacOhdmVpcyBjb3JyZXNwb25kZW50ZXMuDQoNCiogKipWb2PDqioqIGVzcGVjaWZpY2EgcXVhaXMgcGFyZXMgdXNhci4NCiogVW0gcGFyIMOpIHVtYSB2YXJpw6F2ZWwgZGEgdGFiZWxhIGRhIGVzcXVlcmRhIGUgdW1hIHZhcmnDoXZlbCBkYSB0YWJlbGEgZGEgZGlyZWl0YSBvdSB1bSBjb25qdW50byBkZSB2YXJpw6F2ZWlzIGRhIHRhYmVsYSBkYSBlc3F1ZXJkYSBlIGRhIGRpcmVpdGEuDQoqIE9zIGNhc29zIGRldmVtIHRlciB2YWxvcmVzICpleGF0YW1lbnRlIGlndWFpcyogbm8gcGFyIHBhcmEgcXVlIHVtYSBjb3JyZXNwb25kw6puY2lhIHNlamEgZmVpdGEuDQoNClF1YW5kbyBqdW50YW1vcyBjb25qdW50b3MgZGUgZGFkb3MsIG8gZm9ybWF0byBnZXJhbCDDqQ0KDQpgYGB7ciwgZXZhbD1GQUxTRX0NCmxlZnRfZGF0YXNldCAlPiUgDQogIDxKT0lOPihyaWdodF9kYXRhc2V0LCANCiAgICAgICAgIGJ5PTxIT1cgVE8gSk9JTj4pDQpgYGANCm9uZGUgYGxlZnRfZGF0YXNldGAgZWAgcmlnaHRfZGF0YXNldGAgc8OjbyBkYXRhc2V0cywgYDxKT0lOPmAgw6kgbyB0aXBvIGVzcGVjw61maWNvIGRlIGp1bsOnw6NvLCBlIGA8SE9XIFRPIEpPSU4+YCBkw6EgaW5mb3JtYcOnw7VlcyBkZXRhbGhhZGFzIHNvYnJlIGNvbW8gZmF6w6otbG8uDQoNCk8gYXJndW1lbnRvIGBieWAgaW5mb3JtYSBjb21vIGp1bnRhciBvcyBkb2lzIGNvbmp1bnRvcyBkZSBkYWRvcywgZXNwZWNpZmljYW1lbnRlIGNvbSBxdWFpcyB2YXJpw6F2ZWlzIGVsZSBkZXZlIGNvcnJlc3BvbmRlci4gU2UgYXMgdmFyacOhdmVpcyBlc3RpdmVyZW0gb3MgbWVzbW9zIG5vbWVzLCBzw7MgcHJlY2lzYW1vcyBlc2NyZXZlciBvIG5vbWUgZGVzc2EgdmFyacOhdmVsLCBlbnRyZSBhc3BhczogYGJ5ID0iIHZhcmlhYmxlX25hbWUgImAuDQoNClNlIGFzIGR1YXMgdmFyacOhdmVpcyBhIHNlcmVtIGNvcnJlc3BvbmRpZGFzIHTDqm0gbm9tZXMgZGlmZXJlbnRlcyBub3MgZG9pcyBjb25qdW50b3MgZGUgZGFkb3MsIHBvZGVtb3MgZXNjcmV2ZXIgYGJ5ID0gYyAoIiBub21lMSAiPSIgbm9tZTIgIilgLCBvbmRlIGBub21lMWAgw6kgYSB2YXJpw6F2ZWwgbm8gY29uanVudG8gZGUgZGFkb3MgZXNxdWVyZG8gYSBzZXIgY29ycmVzcG9uZGlkbyBhb2Agbm9tZTIgYHZhcmnDoXZlbCBubyBjb25qdW50byBkZSBkYWRvcyBjb3JyZXRvLg0KDQpUYW1iw6ltIHBvZGVtb3MgY29ycmVzcG9uZGVyIGVtIHbDoXJpYXMgdmFyacOhdmVpcyB1c2FuZG8gYGJ5ID0gYyAoIiBub21lMSAiPSIgbm9tZTIgIiwiIG5vbWUxYSAiPSIgbm9tZTJhICIpYCwgb25kZSBvcyBub21lcyDDoCBlc3F1ZXJkYSBkb3MgaWd1YWlzIHPDo28gdmFyacOhdmVpcyBkbyBjb25qdW50byBkZSBkYWRvcyBlc3F1ZXJkbyBlIGFxdWVsZXMgbm8gw6AgZGlyZWl0YSBkb3MgaWd1YWlzIHPDo28gZG8gY29uanVudG8gZGUgZGFkb3MgY2VydG8uDQoNClNlIGBieSA9YCBmb3Igb21pdGlkbyBkZSB1bWEganVuw6fDo28sIGVudMOjbyBgUmAgcmVhbGl6YXLDoSB1bWEgKiBqdW7Dp8OjbyBuYXR1cmFsICosIHF1ZSBjb21iaW5hIG9zIGRvaXMgY29uanVudG9zIGRlIGRhZG9zIHBvciB0b2RhcyBhcyB2YXJpw6F2ZWlzIHF1ZSBlbGVzIHTDqm0gZW0gY29tdW0uIMOJIHVtYSBib2EgcHLDoXRpY2Egc2VtcHJlIGluY2x1aXIgYGJ5ID1gLg0KDQpWYW1vcyBkaXNjdXRpciBvcyBkaWZlcmVudGVzIHRpcG9zIGRlIGp1bsOnw7Vlcy4NCg0KIyMjIE11dGF0aW5nIGpvaW5zDQoNCkEgcHJpbWVpcmEgY2xhc3NlIGRlIGp1bsOnw7VlcyBzw6NvIGp1bsOnw7VlcyBtdXRhbnRlcywgcXVlIGFkaWNpb25hbSBub3ZhcyB2YXJpw6F2ZWlzIChjb2x1bmFzKSDDoCB0YWJlbGEgZGUgZGFkb3MgZXNxdWVyZGEgYSBwYXJ0aXIgZGUgb2JzZXJ2YcOnw7VlcyBjb3JyZXNwb25kZW50ZXMgbmEgdGFiZWxhIGRpcmVpdGEuDQoNCkEgcHJpbmNpcGFsIGRpZmVyZW7Dp2EgbmFzIHRyw6pzIG9ww6fDtWVzIGRlIGp1bsOnw6NvIG11dGFudGUgbmVzdGEgY2xhc3NlIMOpIGNvbW8gZWxhcyByZXNwb25kZW0gw6BzIHNlZ3VpbnRlcyBwZXJndW50YXM6DQoNCjEuIE8gcXVlIGFjb250ZWNlIHF1YW5kbyB1bSBjYXNvIG5hIHRhYmVsYSBkYSBkaXJlaXRhIG7Do28gdGVtIGNvcnJlc3BvbmTDqm5jaWFzIG5hIHRhYmVsYSBkYSBlc3F1ZXJkYT8NCjIuIE8gcXVlIGFjb250ZWNlIHF1YW5kbyB1bSBjYXNvIG5hIHRhYmVsYSBkYSBlc3F1ZXJkYSBuw6NvIHRlbSBjb3JyZXNwb25kw6puY2lhcyBuYSB0YWJlbGEgZGEgZGlyZWl0YT8NCg0KVHLDqnMgZnVuw6fDtWVzIGRlIGp1bsOnw6NvIG11dGFudGVzOg0KDQoqKmBsZWZ0X2pvaW4oKWAgKio6IGEgc2HDrWRhIHRlbSB0b2RvcyBvcyBjYXNvcyBkYSBlc3F1ZXJkYSwgaW5kZXBlbmRlbnRlbWVudGUgc2UgaG91dmVyIHVtYSBjb3JyZXNwb25kw6puY2lhIG5hIGRpcmVpdGEsIG1hcyBkZXNjYXJ0YSBxdWFpc3F1ZXIgY2Fzb3MgbmEgZGlyZWl0YSBxdWUgbsOjbyB0ZW5oYW0gdW1hIGNvcnJlc3BvbmTDqm5jaWEgbmEgZXNxdWVyZGEuIChIw6EgdGFtYsOpbSB1bWEgZnVuw6fDo28gKiogYHJpZ2h0X2pvaW4gKClgICoqIHF1ZSBmYXogbyBvcG9zdG8uKQ0KDQohW0NyZWRpdDogR2FycmljayBBZGVuLUJ1aWUg4oCTIEBncnJyY2tdKGh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9nYWRlbmJ1aWUvdGlkeWV4cGxhaW4vbWFzdGVyL2ltYWdlcy9sZWZ0LWpvaW4uZ2lmKXt3aWR0aD0zMDB9DQoNCg0KKipgaW5uZXJfam9pbigpYCoqOiBhIHNhw61kYSB0ZW0gYXBlbmFzIG9zIGNhc29zIGRhIGVzcXVlcmRhIGNvbSB1bWEgY29ycmVzcG9uZMOqbmNpYSDDoCBkaXJlaXRhLg0KIVtDcmVkaXQ6IEdhcnJpY2sgQWRlbi1CdWllIOKAkyBAZ3JycmNrXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZ2FkZW5idWllL3RpZHlleHBsYWluL21hc3Rlci9pbWFnZXMvaW5uZXItam9pbi5naWYpe3dpZHRoPTMwMH0NCg0KDQoqKmBmdWxsX2pvaW4oKWAqKjphIHNhw61kYSB0ZW0gdG9kb3Mgb3MgY2Fzb3MgZGEgZXNxdWVyZGEgZSBkYSBkaXJlaXRhLiBJc3NvIMOpIG1lbm9zIGNvbXVtIGRvIHF1ZSBvcyBkb2lzIHByaW1laXJvcyBvcGVyYWRvcmVzIGRlIGFzc29jaWHDp8Ojby4NCg0KIVtDcmVkaXQ6IEdhcnJpY2sgQWRlbi1CdWllIOKAkyBAZ3JycmNrXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZ2FkZW5idWllL3RpZHlleHBsYWluL21hc3Rlci9pbWFnZXMvZnVsbC1qb2luLmdpZil7d2lkdGg9MzAwfQ0KDQpRdWFuZG8gaMOhIHbDoXJpYXMgY29ycmVzcG9uZMOqbmNpYXMgbmEgdGFiZWxhIGRhIGRpcmVpdGEgcGFyYSB1bSBjYXNvIGVzcGVjw61maWNvIG5hIHRhYmVsYSBkYSBlc3F1ZXJkYSwgdG9kb3Mgb3MgdHLDqnMgZGVzc2VzIG9wZXJhZG9yZXMgZGUganVuw6fDo28gbXV0YW50ZSBwcm9kdXplbSB1bSBjYXNvIHNlcGFyYWRvIG5hIG5vdmEgdGFiZWxhIHBhcmEgY2FkYSB1bWEgZGFzIGNvcnJlc3BvbmTDqm5jaWFzIGRhIGRpcmVpdGEuDQoNCg0KDQojIyMjIEV4ZW1wbG9zDQoNClByaW1laXJvLCBjcmllIGRvaXMgcGVxdWVub3MgY29uanVudG9zIGRlIGRhZG9zOg0KDQpgYGB7cn0NCmdlbmVyYWxfaW5mbyA8LSB0aWJibGUoDQogIHBlcnNvbl9pZCA9IGMoMSwgMiwgMywgNCwgNSwgNiwgNywgOCwgOSwgMTApLA0KICBhZ2UgPSBjKDM0LCA1NCwgNjcsIDkyLCAyMSwgMzIsIDE4LCA0NSwgMzQsIDU1KSwNCiAgc2l0dWFjYW8gPSBjKCJhbHVndWVsIiwgImFsdWd1ZWwiLCAicHJvcHJpbyIsICJhbHVndWVsIiwgImFsdWd1ZWwiLCAicHJvcHJpbyIsICJhbHVndWVsIiwgInByb3ByaW8iLCAicHJvcHJpbyIsICJwcm9wcmlvIikNCikNCg0KZ2VuZXJhbF9pbmZvDQoNCnBldF9pbmZvIDwtIHRpYmJsZSgNCiAgcGVyc29uX2lkID0gYygyLDMsNSw3LDgsMTAsMTEsMTIsMTMsMTQsMTUpLA0KICBwZXRfb3duZXIgPSBjKCJzaW0iLCAibsOjbyIsICJuw6NvIiwgInNpbSIsICJzaW0iLCAibsOjbyIsICJuw6NvIiwgIm7Do28iLCAic2ltIiwgIm7Do28iLCAibsOjbyIpDQopDQoNCnBldF9pbmZvDQpgYGANCg0KMS4gQ29tZWNlIGNvbSBgZ2VuZXJhbF9pbmZvYCBlIGBsZWZ0X2pvaW4oKWAgbyBgcGV0X2luZm9gIGJ5IGBwZXJzb25faWRgOg0KDQpgYGB7cn0NCmdlbmVyYWxfaW5mbyAlPiUgDQogIGxlZnRfam9pbihwZXRfaW5mbywgDQogICAgICAgICAgICBieSA9ICJwZXJzb25faWQiKQ0KYGBgDQoNCkEgdGFiZWxhIHJlc3VsdGFudGUgdGVtIDEwIGxpbmhhcyBkZSBkYWRvcyAtIGFzIDEwIG9ic2VydmHDp8O1ZXMgZGUgYGdlbmVyYWxfaW5mb2AuIEV4aXN0ZW0gdmFsb3JlcyBhdXNlbnRlcyBwYXJhIGBwZXRfb3duZXJgIHBhcmFgIHBlcnNvbl9pZGAgcXVlIGVzdGF2YW0gbmEgdGFiZWxhIGBnZW5lcmFsX2luZm9gIGUgbsOjbyBuYSB0YWJlbGFgIHBldF9pbmZvYC4NCg0KKiogPz8/ICoqIENvbW8gb3MgcmVzdWx0YWRvcyBtdWRhcmlhbSBzZSBgcmlnaHRfam9pbiAoKWAgZm9zc2UgdXNhZG8gbm8gY8OzZGlnbyBhY2ltYSBlbSB2ZXogZGUgYGxlZnRfam9pbiAoKWA/DQoNCjIuIENvbWVjZSBjb20gYGdlbmVyYWxfaW5mb2AgZWAgaW5uZXJfam9pbiAoKSBgb2AgcGV0X2luZm9gIHBvciBgcGVyc29uX2lkYDoNCg0KYGBge3J9DQpnZW5lcmFsX2luZm8gJT4lIA0KICBpbm5lcl9qb2luKHBldF9pbmZvLCANCiAgICAgICAgICAgICBieSA9ICJwZXJzb25faWQiKQ0KYGBgDQoNCkEgdGFiZWxhIHJlc3VsdGFudGUgdGVtIGFwZW5hcyA2IGxpbmhhcyBjb20gYXMgb2JzZXJ2YcOnw7VlcyBxdWUgZXN0w6NvIGVtIGBnZW5lcmFsX2luZm9gIGVgIHBldF9pbmZvYC4NCg0KMy4gQ29tZWNlIGNvbSBgZ2VuZXJhbF9pbmZvYCBlYCBmdWxsX2pvaW4gKCkgYG9gIHBldF9pbmZvYCBwb3IgYHBlcnNvbl9pZGA6DQoNCmBgYHtyfQ0KZ2VuZXJhbF9pbmZvICU+JSANCiAgZnVsbF9qb2luKHBldF9pbmZvLCANCiAgICAgICAgICAgIGJ5ID0gInBlcnNvbl9pZCIpDQpgYGANCg0KQSB0YWJlbGEgcmVzdWx0YW50ZSBwb3NzdWkgMTUgbGluaGFzLiBFc3TDo28gZmFsdGFuZG8gdmFsb3JlcyBwYXJhIGBwZXRfb3duZXJgIHBhcmFgIHBlcnNvbl9pZGAgcXVlIGVzdGF2YW0gbmEgdGFiZWxhIGBnZW5lcmFsX2luZm9gIGUgbsOjbyBuYSB0YWJlbGFgIHBldF9pbmZvYCwgZSBlc3TDo28gZmFsdGFuZG8gdmFsb3JlcyBwYXJhIGBpZGFkZWAgZWAgYWx1Z3VlbGAgcGFyYSBgcGVyc29uX2lkYCBxdWUgZXN0YXZhbSBuYSB0YWJlbGEgYHBldF9pbmZvYCBlIG7Do28gbmEgdGFiZWxhYCBnZW5lcmFsX2luZm9gLg0KDQojIyMgRmlsdGVyaW5nIGpvaW5zDQoNCkEgc2VndW5kYSBjbGFzc2UgZGUganVuw6fDtWVzIHPDo28ganVuw6fDtWVzIGRlIGZpbHRyYWdlbSwgcXVlIHNlbGVjaW9uYW0gY2Fzb3MgZXNwZWPDrWZpY29zIGRhIHRhYmVsYSBkYSBlc3F1ZXJkYSBjb20gYmFzZSBlbSBzZSBlbGVzIGNvcnJlc3BvbmRlbSBhIHVtYSBvYnNlcnZhw6fDo28gbmEgdGFiZWxhIGRhIGRpcmVpdGEuDQoNCioqIGBzZW1pX2pvaW4gKClgICoqOiBkZXNjYXJ0YSBxdWFpc3F1ZXIgY2Fzb3MgbmEgdGFiZWxhIGRhIGVzcXVlcmRhIHF1ZSBuw6NvIHRlbmhhbSB1bWEgY29ycmVzcG9uZMOqbmNpYSBuYSB0YWJlbGEgZGEgZGlyZWl0YS4gU2UgaG91dmVyIHbDoXJpYXMgY29ycmVzcG9uZMOqbmNpYXMgZGUgY2Fzb3MgZGEgZGlyZWl0YSBwYXJhIHVtIGNhc28gZGEgZXNxdWVyZGEsIGVsZSBtYW50w6ltIGFwZW5hcyB1bWEgY8OzcGlhIGRvIGNhc28gZGEgZXNxdWVyZGEuDQoNCg0KIVtDcmVkaXQ6IEdhcnJpY2sgQWRlbi1CdWllIOKAkyBAZ3JycmNrXShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZ2FkZW5idWllL3RpZHlleHBsYWluL21hc3Rlci9pbWFnZXMvc2VtaS1qb2luLmdpZil7d2lkdGg9MzAwfQ0KDQoqKmBhbnRpX2pvaW4oKWAqKjogZGVzY2FydGEgcXVhaXNxdWVyIGNhc29zIG5hIHRhYmVsYSBkYSBlc3F1ZXJkYSBxdWUgdGVuaGFtIHVtYSBjb3JyZXNwb25kw6puY2lhIG5hIHRhYmVsYSBkYSBkaXJlaXRhLg0KDQoNCiFbQ3JlZGl0OiBHYXJyaWNrIEFkZW4tQnVpZSDigJMgQGdycnJja10oaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2dhZGVuYnVpZS90aWR5ZXhwbGFpbi9tYXN0ZXIvaW1hZ2VzL2FudGktam9pbi5naWYpe3dpZHRoPTMwMH0NCg0KIyMjIyBFeGFtcGxvDQoNCkVsZXMgdXNhbSBvcyBkYWRvcyBkZSBleGVtcGxvIGRhIHNlw6fDo28gYW50ZXJpb3INCg0KVW0gYHNlbWlfam9pbiAoKWAgw6kgdXNhZG8gcGFyYSBlbmNvbnRyYXIgYSBpZGFkZSBlIG8gc3RhdHVzIGRvIGFsdWd1ZWwgKGluZm9ybWHDp8O1ZXMgbmEgdGFiZWxhIGBnZW5lcmFsX2luZm9gKSBwYXJhIG9zIHByb3ByaWV0w6FyaW9zIGRlIGFuaW1haXMgZGUgZXN0aW1hw6fDo286DQoNCmBgYHtyfQ0KZ2VuZXJhbF9pbmZvICU+JSANCiAgc2VtaV9qb2luKHBldF9pbmZvICU+JSBmaWx0ZXIocGV0X293bmVyID09ICJzaW0iKSwgDQogICAgICAgICAgICBieSA9ICJwZXJzb25faWQiKSANCmBgYA0KDQpJc3NvIHJldG9ybmEgdW1hIHRhYmVsYSBjb20gMyBsaW5oYXMuIFVtYSB2ZXogcXVlIHPDo28gbWVzYXMgcGVxdWVuYXMsIHZvY8OqIGRldmUgdmVyaWZpY2FyIGlzc28gbWFudWFsbWVudGUuIE9ic2VydmUgdGFtYsOpbSBxdWUgbsOjbyBwcmVzc2lvbmVpIGVudGVyIGFww7NzIGAlPiVgIGRlbnRybyBkZSBgc2VtaV9qb2luICgpYC4gRXN0ZSDDqSB1bSBjYXNvIGVtIHF1ZSBvIGRlaXhhbW9zIG5hIG1lc21hIGxpbmhhIHBhcmEgdG9ybsOhLWxvIG1haXMgbGVnw612ZWwuDQoNClVzZSB1bSBgYW50aV9qb2luICgpYCBwYXJhIGVuY29udHJhciBhIGlkYWRlIGUgbyBzdGF0dXMgZG8gYWx1Z3VlbCAoaW5mb3JtYcOnw7VlcyBuYSB0YWJlbGEgYGdlbmVyYWxfaW5mb2ApIHBhcmEgcGVzc29hcyBxdWUgbsOjbyBzw6NvIGRvbm9zIGNvbmZpcm1hZG9zIGRlIGFuaW1haXMgZGUgZXN0aW1hw6fDo28gKG9ic2VydmUgcXVlIGlzc28gaW5jbHVpIGRlc2NvbmhlY2lkb3MpOg0KDQpgYGB7cn0NCmdlbmVyYWxfaW5mbyAlPiUgDQogIGFudGlfam9pbihwZXRfaW5mbyAlPiUgZmlsdGVyKHBldF9vd25lciA9PSAic2ltIiksDQogICAgICAgICAgICBieSA9ICJwZXJzb25faWQiKQ0KYGBgDQoNCiMjIyBEZW1vIHZpZGVvDQoNCkFnb3JhIGFzc2lzdGEgYW8gdsOtZGVvIGFiYWl4byBxdWUgaXLDoSBndWnDoS1sbyBwb3IgYWxndW5zIGV4ZW1wbG9zIGRlIGNvZGlmaWNhw6fDo28gbWFpcyBhdmFuw6dhZG9zIChhbMOpbSBkZSB1bWEgcGFydGljaXBhw6fDo28gZXNwZWNpYWwgZGUgbWluaGEgZmlsaGEsIEhhZGxleSkuIE9zIGFycXVpdm9zIFIgTWFya2Rvd24gcGFyYSBkb3dubG9hZCBwYXJhIGFjb21wYW5oYXIgc8OjbyBlbmNvbnRyYWRvcyBhYmFpeG8gZG8gdsOtZGVvIHBpdm90YW50ZS4NCg0KPGlmcmFtZSB3aWR0aD0iNTYwIiBoZWlnaHQ9IjMxNSIgc3JjPSJodHRwczovL3d3dy55b3V0dWJlLmNvbS9lbWJlZC9NSkRIUnR3WmhvTSIgZnJhbWVib3JkZXI9IjAiIGFsbG93PSJhY2NlbGVyb21ldGVyOyBhdXRvcGxheTsgZW5jcnlwdGVkLW1lZGlhOyBneXJvc2NvcGU7IHBpY3R1cmUtaW4tcGljdHVyZSIgYWxsb3dmdWxsc2NyZWVuPjwvaWZyYW1lPg0KDQojIyMgUmVjdXJzb3MNCg0KKiBbQW5pbWF0ZWQgR0lGc10oaHR0cHM6Ly9naXRodWIuY29tL2dhZGVuYnVpZS90aWR5ZXhwbGFpbikgIA0KKiBbUjREUyBDaGFwdGVyIDEzXShodHRwczovL3I0ZHMuaGFkLmNvLm56L3JlbGF0aW9uYWwtZGF0YS5odG1sKSAgDQoqIFtKb2luIENoZWF0c2hlZXRdKGh0dHBzOi8vc3RhdDU0NS5jb20vam9pbi1jaGVhdHNoZWV0Lmh0bWwpIGJ5IEplbm55IEJyeWFuDQoNCg0KIyMjIFN1YSB2ZXohDQoNCiMjIyMgRXhlcmNpc2UgMTogbXV0YXRpbmcgam9pbg0KDQojIyMjIEV4ZXJjw61jaW8gMTogbXV0YcOnw6NvIGRlIGp1bsOnw6NvDQoNClJlc3VtYSBvcyBkYWRvcyBgZ2FyZGVuX2hhcnZlc3RgIHBhcmEgZW5jb250cmFyIGEgY29saGVpdGEgdG90YWwgZW0gbGlicmFzIHBhcmEgY2FkYSB2YXJpZWRhZGUgZGUgdmVnZXRhaXMgZSwgZW0gc2VndWlkYSwgdGVudGUgYWRpY2lvbmFyIGEgcGFyY2VsYSBkYSB0YWJlbGFgIGdhcmRlbl9wbGFudGluZ2AuIElzc28gbsOjbyBzYWlyw6EgcGVyZmVpdGFtZW50ZS4gUXVhbCDDqSBvIHByb2JsZW1hPyBDb21vIHZvY8OqIHBvZGUgY29uc2VydGFyIGlzc28/DQoNCiMjIyMgRXhlcmPDrWNpbyAyOiBtdXRhw6fDo28gZGUganVuw6fDo28NCg0KR29zdGFyaWEgZGUgc2FiZXIgcXVhbnRvIGRpbmhlaXJvICJlY29ub21pemVpIiBjb20gYSBqYXJkaW5hZ2VtLCBwYXJhIGNhZGEgdGlwbyBkZSB2ZWdldGFsLiBEZXNjcmV2YSBjb21vIGV1IHBvZGVyaWEgdXNhciBvcyBjb25qdW50b3MgZGUgZGFkb3MgYGdhcmRlbl9oYXJ2ZXN0YCBlYCBnYXJkZW5fc3BlbmRpbmdgLCBqdW50byBjb20gZGFkb3MgZGUgYWxndW0gbHVnYXIgY29tbyBbZXN0ZV0gKGh0dHBzOi8vcHJvZHVjdHMud2hvbGVmb29kc21hcmtldC5jb20vc2VhcmNoP3NvcnQ9cmVsZXZhbmNlJnN0b3JlPTEwNTQyKSBwYXJhIHJlc3BvbmRlciBhIGVzdGEgcGVyZ3VudGEuIFZvY8OqIHBvZGUgcmVzcG9uZGVyIGlzc28gZW0gcGFsYXZyYXMsIHJlZmVyZW5jaWFuZG8gdsOhcmlhcyBmdW7Dp8O1ZXMgZGUganVuw6fDo28uIFZvY8OqIG7Do28gcHJlY2lzYSBkbyBjw7NkaWdvIFIsIG1hcyBwb2RlIGZvcm5lY2VyIGFsZ3VtIHNlIGZvciDDunRpbC4NCg0KIyMjIyBFeGVyY8OtY2lvIDM6IGp1bsOnw6NvIGRlIGZpbHRyYWdlbQ0KDQpFeGNsdWEgYXMgdmFyaWVkYWRlcyBkZSB2ZWdldGFpcyBkZSBgY29saGVpdGFfZG9famFyZGltYCBxdWUgZXN0w6NvIG5hcyBwYXJjZWxhcyBNIGUgSC4NCg0KYGBge3J9DQoNCmBgYA0K